using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Dapper.Abstractions;

namespace Dapper.Extensions;

public static class ServiceCollectionExtensions
{
	public static IServiceCollection AddDapper(
		this IServiceCollection services,
		Action<DapperBuilder> configure)
	{
		SqlMapper.AddTypeHandler(new GenericArrayHandler<string>());
		var builder = new DapperBuilder(services);
		configure(builder);
		Check.NotNull(builder.Options.ConnectionFactoryStrategy, nameof(builder.Options.ConnectionFactoryStrategy));
		Check.NotEmpty(builder.Options.ConnectionString, nameof(builder.Options.ConnectionString));
		var factory = builder.Options.ConnectionFactoryStrategy
			.CreateConnectionFactory(builder.Options.ConnectionString);
		var compiler = builder.Options.SqlCompilerStrategy
			.CreateCompiler();
		
		// 装饰器顺序：日志装饰器在内层，重试装饰器在外层
		if (builder.Options.EnableLogging)
		{
			services.AddSingleton<IDbConnectionFactory>(provider =>
			{
				var logger = provider.GetRequiredService<ILogger<IDbConnectionFactory>>();
				var loggedFactory = new LoggingDbConnectionDecorator(factory, logger, builder.Options.LoggingConfiguration);
				
				// 如果启用重试，将重试装饰器包装在日志装饰器外层
				if (builder.Options.EnabledRetry)
				{
					return new RetryDbConnectionFactoryDecorator(loggedFactory, builder.Options.Retry);
				}
				
				return loggedFactory;
			});
		}
		else if (builder.Options.EnabledRetry)
		{
			// 只启用重试，没有日志
			factory = new RetryDbConnectionFactoryDecorator(factory, builder.Options.Retry);
			services.AddSingleton(factory);
		}
		else
		{
			// 都没启用，使用原始工厂
			services.AddSingleton(factory);
		}
		services.AddSingleton<ISqlBuilder>(_ => new SqlBuilderWrapper(compiler));
		return services;
	}
}
